home *** CD-ROM | disk | FTP | other *** search
-
-
- /*
- PBUTILS.C Phonebook Library internal utilities
- */
-
-
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <malloc.h>
- #include <phonebk.h>
-
- /*
- PBLIB Internal Utility: EntryOkToAdd()
-
- Performs some validity checks on a phonebook entry for adding.
-
- INPUT: A phonebook, and the entry.
-
- OUTPUT: 1 or 0.
- */
-
- char * pascal EntryOkToAdd(PB *pb, PBE *entry)
- {
- int i, j, k;
- char *fields;
- int *members;
- PBEFIXED fixed_part, *result;
- char *return_buffer;
-
- Pberrno = 0; /* Initially, always reset */
-
- /* Check that the name field is neither empty, only blank(s), or too long */
- for (i=0; entry->name[i] && (i < NAMELENGTH); i++) {
- if (entry->name[i] != ' ') {
- break;
- }
- }
- if ((!entry->name[i]) || (i == NAMELENGTH)) {
- return(NULL);
- }
-
- /* Check all the entries for a possible name match with the new entry */
- for (i=0; i<MAXENTRIES; i++) {
- if (GetFixedPart(pb, &fixed_part, i)) {
- if (!strnicmp(entry->name, fixed_part.name, NAMELENGTH)) {
- Pberrno = DUPLICATEENTRY;
- return(NULL);
- }
- }
- }
-
- /* Checks specific to person entries */
- if (entry->type == PERSONENTRY) {
-
- /* New entries can have members only if they are group entries */
- if (entry->members) {
- return(NULL);
- }
-
- /* check that the phone number is present and valid. */
- /* (If the first character of phone number is 'm' or 'M', rest is ok) */
- if (tolower(entry->PhoneNumber[0]) != 'm') {
- for (i=0; entry->PhoneNumber[i] && (i < PHONENUMLENGTH); i++) {
- if ((entry->PhoneNumber[i] >= '0') &&
- (entry->PhoneNumber[i] <= '9')) {
- break;
- }
- }
- if ((!entry->PhoneNumber[i]) || (i == PHONENUMLENGTH)) {
- return(NULL);
- }
- }
-
- /* check that entry has pb->fields ASCIIZ fields */
- for (i=0, k=0; i<pb->header.fields; i++, k++) {
- if (!(entry->fields[i])) {
- break;
- }
- for (j=0; j<MAXFIELDSIZE; j++, k++) {
- if (!entry->fields[i][j]) {
- break;
- }
- }
- if (j == MAXFIELDSIZE) {
- return(NULL);
- }
- }
- if (i<pb->header.fields) {
- return(NULL);
- }
-
- /* finally, length is not checked, but set (assume no members list.) */
- entry->length = sizeof(PBEFIXED) + k;
- }
-
- /* Now, the checks for group entries */
- else if (entry->type == GROUPENTRY) {
-
- /* Check that the members are in the phonebook and are person entries */
- if (entry->members) {
- for (i=0; i<entry->members; i++) {
- if (!(result = GetFixedPart(pb, &fixed_part, entry->MemberList[i]))) {
- return(NULL);
- }
- if (fixed_part.type != PERSONENTRY) {
- return(NULL);
- }
- }
-
- /* And, because PbAddEntry will use PbAddToGroup, null out membership */
- entry->members = 0;
- }
-
- /* check that the phone number field is all NULL */
- for (i=0; i<PHONENUMLENGTH; i++) {
- if (entry->PhoneNumber[i]) {
- return(NULL);
- }
- }
-
- /* The entry length is not checked, but set */
- entry->length = sizeof(PBEFIXED); /* space for members list NOT included */
- }
- else {
- return(NULL); /* invalid type */
- }
-
- /* If all that passed, we must be ok, fill in the return buffer! */
- if (!(return_buffer = (char *)malloc(entry->length))) {
- Pberrno = OUTOFMEM;
- return(NULL);
- }
- memcpy(return_buffer, entry, sizeof(PBEFIXED));
- if (entry->type == PERSONENTRY) {
- fields = return_buffer + sizeof(PBEFIXED);
- for (i=0, j=0; i<pb->header.fields; i++, j++) {
- for (k=0; fields[j] = entry->fields[i][k]; j++, k++) {
- ;
- }
- }
- }
- return(return_buffer);
- }
-
- /*
- PBLIB Internal Utility: GetFixedPart()
-
- Gets the fixed part of a phonebook entry, given the record id.
-
- INPUT: The phonebook, a buffer to read the entry into, and the record id.
-
- OUTPUT: The entry information, if the offset was non-NULL at that record id.
- If an error occurs, Pberrno is set, and function returns NULL.
- If no error occurs, function returns the same pointer it was given.
- If the offset at that record id was NULL, (no record there), function
- returns NULL, but Pberrno is NOT set.
-
- */
-
- PBEFIXED * pascal GetFixedPart(PB *pb, PBEFIXED *retinfo, WORD rid)
- {
- size_t buffed_rids;
- long offset;
- int red; /* for return value of fread() */
-
- Pberrno = 0; /* Initially, always reset */
-
- /* First, get the offset */
- offset = OffsetOfEntry(pb, rid);
-
- /* Once the offset is gotten, go there, and read the entry */
- if (!offset) {
- return(NULL);
- }
- if (fseek(pb->fp, offset, SEEK_SET)) {
- Pberrno = FSEEKERROR;
- return(NULL);
- }
- red = fread(retinfo, 1, sizeof(PBEFIXED), pb->fp);
- if (red != sizeof(PBEFIXED)) {
- Pberrno = CANTREAD;
- return(NULL);
- }
- return(retinfo);
- }
-
- /*
- PBLIB Internal Utility: EntryOkToChange()
-
- Performs validity checks on a proposed change to an entry.
-
- INPUT: A phonebook, the old entry, and a proposed changed entry.
-
- OUTPUT: Returns pointer to buffer containing the changed entry, in the
- format used in the phonebook file, not as a PBE.
- */
-
- char *pascal EntryOkToChange(PB *pb, PBE *old_entry, PBE *new_entry)
- {
- int i, j, k;
- PBEFIXED fixed_part;
- char *return_buffer;
- char *fields;
- int *members;
-
- Pberrno = 0; /* Initially, always reset */
-
- /* Change of entry type not allowed */
- if (old_entry->type != new_entry->type) {
- return(NULL);
- }
-
- /* If name is changed, ...*/
- if (strnicmp(old_entry->name, new_entry->name, NAMELENGTH)) {
-
- /* ... it may not be empty, nor all blank(s), nor too long */
- for (i=0; new_entry->name[i] && (i < NAMELENGTH); i++) {
- if (new_entry->name[i] != ' ') {
- break;
- }
- }
- if ((!new_entry->name[i]) || (i == NAMELENGTH)) {
- return(NULL);
- }
-
- /* ... nor may it match any other entry's name */
- for (i=0; i<MAXENTRIES; i++) {
- if (GetFixedPart(pb, &fixed_part, i)) {
- if (!(strnicmp(new_entry->name, fixed_part.name, NAMELENGTH))) {
- Pberrno = DUPLICATEENTRY;
- return(NULL);
- }
- }
- }
- }
-
- /* No changes to membership count or members list allowed */
- if (old_entry->members != new_entry->members) {
- return(NULL);
- }
- for (i=0; i<old_entry->members; i++) {
- if (old_entry->MemberList[i] != new_entry->MemberList[i]) {
- return(NULL);
- }
- }
-
- /* Checks specific to group entries */
- if (old_entry->type == GROUPENTRY) {
-
- /* Actually, no fields but name may change, but rest are covered elsewhere*/
- if ((old_entry->length != new_entry->length) ||
- (old_entry->HardwareType != new_entry->HardwareType)) {
- return(NULL);
- }
-
- /* The 'PhoneNumber' field for groups must remain all NULL's */
- for (i=0; i<PHONENUMLENGTH; i++) {
- if (new_entry->PhoneNumber[i]) {
- return(NULL);
- }
- }
- }
-
- /* Checks specific to person entries */
- else {
-
- /* check that the phone number is present and valid. */
- /* (If the first character of phone number is 'm' or 'M', rest is ok) */
- if (tolower(new_entry->PhoneNumber[0]) != 'm') {
- for (i=0; new_entry->PhoneNumber[i] && (i < PHONENUMLENGTH); i++) {
- if ((new_entry->PhoneNumber[i] >= '0') ||
- (new_entry->PhoneNumber[i] <= '9')) {
- break;
- }
- }
- if ((!new_entry->PhoneNumber[i]) || (i == PHONENUMLENGTH)) {
- return(NULL);
- }
- }
-
- /* check that entry has pb->fields ASCIIZ fields */
- for (i=0, k=0; i<pb->header.fields; i++, k++) {
- if (!(new_entry->fields[i])) {
- break;
- }
- for (j=0; j<MAXFIELDSIZE; j++, k++) {
- if (!new_entry->fields[i][j]) {
- break;
- }
- }
- if (j == MAXFIELDSIZE) {
- return(NULL);
- }
- }
- if (i<pb->header.fields) {
- return(NULL);
- }
-
- /* Set the length based on sizeof fixed part, plus fields and members */
- new_entry->length = sizeof(PBEFIXED) + k +
- new_entry->members * sizeof(int);
-
- /* Only person entries may change size, so check here if the new
- entry is larger. The size of the old entry must not put the
- phonebook's 'unused bytes' over the limit */
- if (new_entry->length > old_entry->length) {
- if (pb->header.FreeBytes + old_entry->length
- > MAXUNUSEDBYTES) {
- return(NULL);
- }
- }
- }
-
- /* If all that passed, we must be ok, fill in the return buffer! */
- if (!(return_buffer = (char *)malloc(new_entry->length))) {
- Pberrno = OUTOFMEM;
- return(NULL);
- }
- memcpy(return_buffer, new_entry, sizeof(PBEFIXED));
- fields = return_buffer + sizeof(PBEFIXED);
- if (new_entry->type == PERSONENTRY) {
- for (i=0, j=0; i<pb->header.fields; i++, j++) {
- for (k=0; fields[j] = new_entry->fields[i][k]; j++, k++) {
- ;
- }
- }
- }
- else j = 0;
- members = (int *)&fields[j];
- for (i=0; i<new_entry->members; i++) {
- members[i] = new_entry->MemberList[i];
- }
- return(return_buffer);
- }
-
- /*
- PBLIB Internal Utility: OffsetOfEntry()
-
- Finds the offset of an entry, given its record id. Uses the Pb Offset
- buffer if it is present.
-
- INPUT: A phonebook and the record id of the entry to find the offset of.
-
- OUTPUT: Returns the LONGWORD offset.
- */
-
- LONGWORD pascal OffsetOfEntry(PB *pb, WORD rid)
- {
- int buffed_rids;
- LONGWORD offset;
- int red; /* for returns from fread() */
-
- Pberrno = 0; /* Initially, always reset */
-
- if (pb->OBuffer) { /* IF buffering is ON */
- buffed_rids = pb->OBufferSize/sizeof(LONGWORD);
-
- /* First, if the requested rid is NOT in the buffer, fetch needed section */
- if ((rid < pb->FirstOBufferRID) ||
- (rid > pb->FirstOBufferRID + buffed_rids - 1)) {
- pb->FirstOBufferRID = 0;
- while (rid > pb->FirstOBufferRID + buffed_rids - 1) {
- pb->FirstOBufferRID += buffed_rids;
- }
- if (fseek(pb->fp,
- 160L + pb->FirstOBufferRID * sizeof(LONGWORD),
- SEEK_SET)) {
- Pberrno = FSEEKERROR;
- return(NULL);
- }
- red = fread(pb->OBuffer, sizeof(LONGWORD), buffed_rids, pb->fp);
- if (red != buffed_rids) {
- Pberrno = CANTREAD;
- return(NULL);
- }
- }
- return(pb->OBuffer[rid - pb->FirstOBufferRID]);
- }
-
- /* If no buffering, just seek to the needed spot, and read the offset */
- else {
- if (fseek(pb->fp, 160L + rid * sizeof(LONGWORD), SEEK_SET)) {
- Pberrno = FSEEKERROR;
- return(NULL);
- }
- red = fread(&offset, sizeof(LONGWORD), 1, pb->fp);
- if (red != 1) {
- Pberrno = CANTREAD;
- return(NULL);
- }
- return(offset);
- }
- }
-
- /*
- PBLIB Internal Utility: HardwareTypeOf()
-
- Determines whether the HardwareType of an entry at a given record id is HASCCC
- or FAXONLY.
-
- INPUT: A phonebook and the record id of the entry to find the HardwareType of,
- and a pointer to a LONGWORD for returning the offset of the HardwareType
- field.
-
- OUTPUT: Returns HASCCC or FAXONLY, and sets the offset to the entry's
- HardwareType field.
- */
-
- BYTE pascal HardwareTypeOf(PB *pb, WORD RecordID, LONGWORD *offset)
- {
- BYTE HardwareType = 0; /* Invalid HardwareType is default if error occurs */
-
- Pberrno = 0; /* Initially, always reset */
-
- *offset = OffsetOfEntry(pb, RecordID) + 7L;
- if (fseek(pb->fp, *offset, SEEK_SET)) {
- Pberrno = FSEEKERROR;
- }
- if (fread(&HardwareType, 1, sizeof(BYTE), pb->fp) != 1) {
- Pberrno = CANTREAD;
- }
- return(HardwareType);
- }